
#include <BEntry>
#include <BFolder>
#include <BReadWrite>
#include <BIcon>
#include "member_BIcon.h"
#include "IGlobal.h"

using namespace BWE;

#define member					(*(member_BIcon*)_ptr)
#define member_allocate()		_ptr = new member_BIcon(this)
#define member_release()		delete (member_BIcon*)_ptr

BIcon::BIcon()
{
	member_allocate();
}
BIcon::BIcon(BImage* image)
{
	member_allocate();
	member.images[State_None] = image;
	member.images[State_Normal] = image;
	member.images[State_Actived] = image;
}
BIcon::BIcon(const BString& fileName)
{
	member_allocate();
	reset(fileName);
}
BIcon::BIcon(const BIcon& other)
{
	member_allocate();
	this->copy(&other);
}
BIcon::~BIcon()
{
	member_release();
}

void BIcon::copy(const BIcon* other)
{
	this->setName(other->name());
	member.fileName = icon_member(other)->fileName;
	for (int i = 0; i < State_Max; i++)
	{
		member.images[i] = icon_member(other)->images[i];
	}
}
BIcon* BIcon::clone() const
{
	return new BIcon(*this);
}

bool BIcon::reset(const BString& fileName)
{
	clear();
	if (fileName.empty())
		return false;

	if (fileName.ext())
	{
		if (BImage* image = ReadFile<BImage>(fileName))
		{
			member.images[State_None] = image;
			member.images[State_Normal] = image;
			member.images[State_Actived] = image;
			return true;
		}
		if (ReadFile(fileName, this))
		{
			member.fileName = fileName;
			if (this->checks(Signal_FileNameChanged))
				this->emit(Signal_FileNameChanged, fileName);
			return true;
		}
	}

	BMap<State, BImageHolder> imageMap;
	int split = fileName.find('|');
	if (split < fileName.size())
	{
		BString temp;
		fileName.substr(temp, 0, split);
		temp.trimmed();
		BImage* image = ReadFile<BImage>(temp);
		if (!image)
			return false;

		BString splitText;
		fileName.substr(splitText, split + 1);
		int end = splitText.find(',');
		splitText.substr(temp, 0, end);

		temp.lower();
		int row = 0;
		int column = 0;
		BStringArray words;
		temp.split(words, '*');
		if (words.size() != 2 || !words[0].isNumber() || !words[1].isNumber())
		{
			printf("Read Icon failed : split info is invalid : %s.\n", temp.cstr());
			return false;
		}
		row = words[0].toInt();
		column = words[1].toInt();

		splitText.truncate(end + 1);
		splitText.split(words, ',');
		if (words.empty())
		{
			printf("Read Icon failed : too less states : %s.\n", fileName.cstr());
			return false;
		}

		BTable<BImageHolder> imageTable(row, column);
		SplitImage(image, imageTable);
		for (int i = 0; i < words.size(); i++)
		{
			BString word = words[i];
			word.trimmed();
			if (word.empty())
				continue;
			word.prepend('-');
			State state = StringToState(word);
			BImage* image = 0;
			int colon_pos = word.find(':');
			if (colon_pos == word.size())
			{
				image = imageTable.at(i);
			}
			else
			{
				temp.reset();
				temp.append(word, 0, colon_pos);
				temp.trimmed();
				state = StringToState(temp);
				word.remove(0, colon_pos + 1);
				int split = word.find('*');
				if (split < word.size())
				{
					int row = word.toInt();
					word.remove(0, split + 1);
					int column = word.toInt();
					image = imageTable.at(row - 1, column - 1);
				}
				else
				{
					int index = word.toInt();
					image = imageTable.at(index - 1);
				}
			}
			if (state == State_Max)
			{
				printf("Read Icon failed : split image failed, bad state : %s.\n", words[i].cstr());
				return false;
			}
			if (image == 0)
			{
				printf("Read Icon failed : split image failed, bad index : %s.\n", words[i].cstr());
				return false;
			}
			imageMap[state] = image;
		}
	}
	else
	{
		const char* name = fileName.name();
		BString path = fileName.path();
		BFolder folder(path);
		if (folder.open())
		{
			for (int i = 0; i < folder.entryCount(); i++)
			{
				BEntry* entry = folder.entry(i);
				if (entry->attrib() != Attrib_File)
					continue;
				if (!entry->name().beginWith(name) || !entry->name().ext())
					continue;
				const BString& test = entry->name();
				State state = StringToState(entry->name());
				imageMap[state] = ReadFile<BImage>(entry->path());
			}
		}
		else
		{
			auto begin = app_resources >= fileName;
			auto end = app_resources <= fileName + '~';
			BString temp;
			for (auto it = begin; it <= end; ++it)
			{
				temp.reset();
				temp << it.key();
				temp.remove(fileName);
				if (temp.contain('/'))
					continue;
				if (!temp.ext())
					continue;
				State state = StringToState(temp);
				if (state == State_None && !temp.beginWith('.'))
					continue;
				imageMap[state] = ReadFile<BImage>(it.key());
			}
		}
	}

	if (imageMap.empty())
		return false;

	InitImageMap(imageMap);

	for (auto it = imageMap.begin(); it.valid(); ++it)
	{
		State state = it.key();
		BImage* image = it.value();
		member.images[state] = image;
	}
	return true;
}

void BIcon::setFileName(const BString& fileName)
{
	if (member.fileName != fileName)
	{
		member.fileName = fileName;
		if (this->checks(Signal_FileNameChanged))
			this->emit(Signal_FileNameChanged, fileName);
	}
}
const BString& BIcon::fileName() const
{
	return member.fileName;
}

bool BIcon::setImage(BImage* image, State state)
{
	if (state >= State_None && state < State_Max)
	{
		if (state == State_None)
		{
			member.images[State_None] = image;

			member.images[State_Normal] = image;
			member.images[State_Normal_Hovered] = image;
			member.images[State_Normal_Pressed] = image;
			member.images[State_Normal_Selected] = image;

			member.images[State_Actived] = image;
			member.images[State_Actived_Hovered] = image;
			member.images[State_Actived_Pressed] = image;
			member.images[State_Actived_Selected] = image;

			member.images[State_Checked] = image;
			member.images[State_Checked_Hovered] = image;
			member.images[State_Checked_Pressed] = image;
			member.images[State_Checked_Selected] = image;

			member.images[State_Disable] = image;
			member.images[State_Disable_Hovered] = image;
			member.images[State_Disable_Pressed] = image;
			member.images[State_Disable_Selected] = image;

			member.images[State_Hovered] = image;
			member.images[State_Pressed] = image;
			member.images[State_Selected] = image;

			return true;
		}
		if (state == State_Normal)
		{
			member.images[State_None] = image;
			member.images[State_Normal] = image;
			member.images[State_Normal_Hovered] = image;
			member.images[State_Normal_Pressed] = image;
			member.images[State_Normal_Selected] = image;
			return true;
		}
		if (state == State_Actived)
		{
			member.images[State_Actived] = image;
			member.images[State_Actived_Hovered] = image;
			member.images[State_Actived_Pressed] = image;
			member.images[State_Actived_Selected] = image;
			return true;
		}
		if (state == State_Checked)
		{
			member.images[State_Checked] = image;
			member.images[State_Checked_Hovered] = image;
			member.images[State_Checked_Pressed] = image;
			member.images[State_Checked_Selected] = image;
			return true;
		}
		if (state == State_Disable)
		{
			member.images[State_Disable] = image;
			member.images[State_Disable_Hovered] = image;
			member.images[State_Disable_Pressed] = image;
			member.images[State_Disable_Selected] = image;
			return true;
		}

		if (state == State_Hovered)
		{
			member.images[State_Hovered] = image;
			member.images[State_Normal_Hovered] = image;
			member.images[State_Actived_Hovered] = image;
			member.images[State_Checked_Hovered] = image;
			member.images[State_Disable_Hovered] = image;
			return true;
		}
		if (state == State_Pressed)
		{
			member.images[State_Pressed] = image;
			member.images[State_Normal_Pressed] = image;
			member.images[State_Actived_Pressed] = image;
			member.images[State_Checked_Pressed] = image;
			member.images[State_Disable_Pressed] = image;
			return true;
		}
		if (state == State_Selected)
		{
			member.images[State_Selected] = image;
			member.images[State_Normal_Selected] = image;
			member.images[State_Actived_Selected] = image;
			member.images[State_Checked_Selected] = image;
			member.images[State_Disable_Selected] = image;
			return true;
		}
		member.images[state] = image;
		return true;
	}
	return false;
}
bool BIcon::setImage(const BString& fileName, State state)
{
	if (state >= State_None && state < State_Max)
	{
		BImage* image = ReadFile<BImage>(fileName);
		if (!image)
			return false;
		return setImage(image, state);
	}
	return false;
}

const BImage* BIcon::image(State state) const
{
	if (state >= State_None && state < State_Max)
	{
		if (member.images[state] == 0)
			member.makeImage(state);
		return member.images[state];
	}
	return 0;
}
BImage* BIcon::image(State state)
{
	if (state >= State_None && state < State_Max)
	{
		if (member.images[state].empty())
			member.makeImage(state);
		return member.images[state];
	}
	return 0;
}

bool BIcon::empty() const
{
	for (int i = State_None; i < State_Max; i++)
	{
		if (member.images[i])
			return false;
	}
	return true;
}
void BIcon::clear()
{
	for (int i = 0; i < State_Max; i++)
	{
		member.images[i] = 0;
	}
}

